package com.vcc.channel.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.vcc.channel.base.channel.LlResult;
import com.vcc.channel.base.config.BaseConfig;
import com.vcc.channel.base.model.request.*;
import com.vcc.channel.base.model.response.*;
import com.vcc.channel.base.util.RsaUtil;
import com.vcc.channel.config.ChannelConfig;
import com.vcc.channel.service.service.LlService;
import com.vcc.core.constant.CardStatusEnum;
import com.vcc.core.constant.CardTypeEnum;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.HttpUtil;
import com.vcc.data.entity.CardType;
import com.vcc.data.entity.UserCard;
import com.vcc.service.service.CardOrderService;
import com.vcc.service.service.CardTypeService;
import com.vcc.service.service.UserCardService;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Log4j2
@Service("LL")
public class LlServiceImpl implements LlService {

    @Resource
    private ChannelConfig channelConfig;
    @Resource
    private CardTypeService cardTypeService;
    @Resource
    private CardOrderService cardOrderService;
    @Resource
    private UserCardService userCardService;

    @Value("${spring.profiles.active:dev}")
    private String activeProfile;

    private BaseConfig getLlConfig() {
        return channelConfig.getLl();
    }

    private String getAuthorization() {
        return "Basic " +
                Base64.encode(
                        getLlConfig().getAppId() +
                                ":" +
                                getLlConfig().getAppSecret()
                );
    }

    private HashMap<String, String> createGetHeader(
            String uri,
            HashMap<String, Object> params
    ) {
        return getHeader(
                Method.GET,
                uri,
                DateUtil.currentSeconds(),
                null,
                params
        );
    }

    private HashMap<String, String> createPostHeader(
            String uri,
            HashMap<String, Object> requestBody
    ) {
        return getHeader(
                Method.POST,
                uri,
                DateUtil.currentSeconds(),
                requestBody,
                null
        );
    }

    private HashMap<String, String> createDeleteHeader(
            String uri
    ) {
        return getHeader(
                Method.DELETE,
                uri,
                DateUtil.currentSeconds(),
                null,
                null
        );
    }

    private HashMap<String, String> getHeader(
            Method method,
            String uri,
            Long timestamp,
            HashMap<String, Object> requestBody,
            HashMap<String, Object> params
    ) {
        log.info("参与签名的数据: ");
        log.info("请求方法: {}", method.name());
        log.info("请求地址: {}", uri);
        log.info("请求时间戳: {}", timestamp);
        if (requestBody != null && !requestBody.isEmpty()) {
            log.info("请求体: {}", JSONUtil.toJsonStr(requestBody));
        }
        if (params != null && !params.isEmpty()) {
            log.info("请求参数: {}", JSONUtil.toJsonStr(params));
        }
        // 对请求地址进行URL编码

        StrBuilder signBuilder = new StrBuilder();
        signBuilder.append(method.name()).append("&");
        signBuilder.append(uri).append("&");
        signBuilder.append(timestamp).append("&");
        if (method.equals(Method.POST) || method.equals(Method.PUT)) {
            if (requestBody != null && !requestBody.isEmpty()) {
                signBuilder.append(JSONUtil.toJsonStr(requestBody));
            }
        } else {
            if (params != null && !params.isEmpty()) {
                signBuilder.append("&");
                StrBuilder signParamsBuilder = new StrBuilder();
                params.forEach((key, value) ->
                        signParamsBuilder.append(key).append("=").append(value).append("&")
                );
                signParamsBuilder.delTo(signParamsBuilder.length() - 1);
                // 去掉最后一个 '&'
                String tempParams = signParamsBuilder.toString();
                //对 & = 空格 进行URL编码
//                tempParams = tempParams.replace("&", "%26")
//                        .replace("=", "%3D")
//                        .replace(":", "%3A")
//                        .replace(" ", "+");
                signBuilder.append(URLEncoder.encode(tempParams, Charset.defaultCharset()));

            }
        }
        log.debug("签名内容: {}", signBuilder.toString());
        String sign = RsaUtil.sha256Sign(
                signBuilder.toString(),
                getLlConfig().getPrivateKey()
        );
        log.debug("签名结果: {}", sign);
        HashMap<String, String> header = HttpUtil.createHeader();
        header.put("Content-Type", "application/json");
        header.put("Authorization", getAuthorization());
        header.put("LLPAY-Signature", "t=" + timestamp + ",v=" + sign);
        return header;
    }

    private LlResult checkResponse(String response, Boolean hasException) {
        LlResult llResult = JSONUtil.toBean(response, LlResult.class);
        if (llResult.hasError() && hasException) {
            throw new ProgramException("请求失败: " + llResult.getMessage());
        }
        return llResult;
    }


    @Override
    public Object openCard(HashMap<String, Object> requestParams) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("currency", "USD");
        requestBody.put("singleLimit", "10000");
        requestBody.put("lifeTimeLimit", "0.00");
        requestBody.put("cardName", requestParams.get("requestId"));
        requestBody.put("cardBinName", requestParams.get("cardBin"));
        requestBody.put("email", "all-win@allwins-ads.com");
        requestBody.put("settleCurrencyCode", "USD");
        try {
            String response = HttpUtil.post(
                    getLlConfig().getUrl(getLlConfig().getOpenCardUrl()),
                    createPostHeader(
                            getLlConfig().getOpenCardUrl(),
                            requestBody
                    ),
                    requestBody
            );
            LlResult llResult = checkResponse(response, false);
            if (llResult.hasError()) {
                log.error("创建卡失败: {}", llResult.getMessage());
                cardOrderService.openCardComplete(
                        requestParams.get("requestId").toString(),
                        null,
                        null,
                        "FAIL"
                );
                throw new ProgramException("开卡失败 ");
            }
            JSONObject data = llResult.dataToEntity(JSONObject.class);
            if (data.getString("status").equals("VALID")) {
                CardType cardType = cardTypeService.getById(Long.valueOf(requestParams.get("cardTypeId").toString()));
                CardSecretVo cardSecretVo = queryCardSecret(
                        data.getString("cardId"),
                        data.getString("cardNo"),
                        data.getString("expiryDate")
                );
                UserCard userCard = new UserCard();
                userCard.setCardNumber(data.getString("cardNo"));
                userCard.setCardNumberLastFour(data.getString("cardNo").substring(data.getString("cardNo").length() - 4));
                userCard.setVcc(cardSecretVo.getCvv());
                userCard.setExpiry(
                        "20" + data.getString("expiryDate").substring(2)
                                + "-" +
                                data.getString("expiryDate").substring(0, 2)
                );
                userCard.setRequestDate(new Date());
                userCard.setCardGroupId(requestParams.containsKey("groupId") ? Long.valueOf(requestParams.get("groupId").toString()) : null);
                userCard.setOrderId(requestParams.get("requestId").toString());
                userCard.setCardType(CardTypeEnum.NORMAL.getCode());
                userCard.setCardTypeId(Long.valueOf(requestParams.get("cardTypeId").toString()));
                userCard.setUserId(Long.valueOf(requestParams.get("userId").toString()));
                userCard.setChannelCardId(data.getString("cardId"));
                userCard.setChannelCode(cardType.getChannelName());
                userCard.setCurrencyCode(cardType.getCurrencyCode());
                userCard.setCurrencyName(cardType.getCurrencyName());
                userCard.setCardType(cardType.getCardLabel());
                userCard.setUsableQuota(BigDecimal.valueOf(0));
                userCard.setRemark(requestParams.containsKey("remark") ? requestParams.get("remark").toString() : "");
                userCard.setCardStatus("ACTIVE");
                userCard.setSumCount(0);
                userCard.setSuccessCount(0);
                userCard.setErrorCount(0);
                userCard.setSumAmount(BigDecimal.valueOf(0));
                userCard.setSuccessAmount(BigDecimal.valueOf(0));
                userCard.setErrorAmount(BigDecimal.valueOf(0));
                userCard.setCardholderId(Long.valueOf(requestParams.get("alCardholderId").toString()));
                userCardService.save(userCard);
                cardOrderService.openCardComplete(
                        requestParams.get("requestId").toString(),
                        userCard.getCardNumber(),
                        userCard.getId(),
                        "SUCCESS"
                );
                return true;

            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("创建卡失败", e);
            throw new ProgramException("创建卡失败");
        }
    }

    @Override
    public Object openShareCard(HashMap<String, Object> requestParams) {
        return null;
    }

    @Override
    public Boolean recharge(CardRechargeDto cardRechargeDto) {
        CardInfoVo cardInfoVo = queryCardInfo(cardRechargeDto.getChannelCardId());
        if (!cardInfoVo.getCardStatus().equals(CardStatusEnum.ACTIVE.getCode())) {
            log.error("卡状态异常，无法充值: {}", cardInfoVo.getCardStatus());
            cardOrderService.rechargeCardComplete(
                    cardRechargeDto.getRequestId(),
                    cardRechargeDto.getCardNumber(),
                    cardRechargeDto.getCardNumberId(),
                    "FAIL"
            );
            throw new ProgramException("卡状态异常，无法充值");
        }
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        HashMap<String, Object> cardControlRules = MapUtil.newHashMap();
        cardControlRules.put("lifeTimeBillAmtLimit", cardInfoVo.getTotalLimit()
                .add(cardRechargeDto.getRechargeAmount())
                .setScale(2, RoundingMode.HALF_UP)
                .toString());
        requestBody.put("cardControlRules", cardControlRules);

        String uri = getLlConfig().getRechargeUrl().replace("{cardId}", cardRechargeDto.getChannelCardId());
        String response = HttpUtil.post(
                getLlConfig().getUrl(uri),
                createPostHeader(
                        uri,
                        requestBody
                ),
                requestBody
        );
        LlResult llResult = checkResponse(response, false);
        if (llResult.hasSuccess()) {
            userCardService.updateUsableQuotaByChannelCardId(
                    cardInfoVo.getBalance().add(cardRechargeDto.getRechargeAmount()),
                    cardInfoVo.getChannelCardId()
            );
        }
        return cardOrderService.rechargeCardComplete(
                cardRechargeDto.getRequestId(),
                cardRechargeDto.getCardNumber(),
                cardRechargeDto.getCardNumberId(),
                llResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );

    }

    @Override
    public Boolean withdraw(CardWithdrawDto cardWithdrawDto) {
        CardInfoVo cardInfoVo = queryCardInfo(cardWithdrawDto.getChannelCardId());
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        HashMap<String, Object> cardControlRules = MapUtil.newHashMap();
        cardControlRules.put("lifeTimeBillAmtLimit",
                cardInfoVo.getTotalLimit()
                        .subtract(cardWithdrawDto.getWithdrawAmount())
                        .setScale(2, RoundingMode.HALF_UP)
                        .toString()
        );
        requestBody.put("cardControlRules", cardControlRules);
        String uri = getLlConfig().getRechargeUrl().replace("{cardId}", cardWithdrawDto.getChannelCardId());
        String response = HttpUtil.post(
                getLlConfig().getUrl(uri),
                createPostHeader(
                        uri,
                        requestBody
                ),
                requestBody
        );
        LlResult llResult = checkResponse(response, false);
        if (llResult.hasSuccess()) {
            userCardService.updateUsableQuotaByChannelCardId(
                    cardInfoVo.getBalance().subtract(cardWithdrawDto.getWithdrawAmount()),
                    cardInfoVo.getChannelCardId()
            );
        }
        return cardOrderService.withdrawCardComplete(
                cardWithdrawDto.getRequestId(),
                cardWithdrawDto.getCardNumber(),
                cardWithdrawDto.getCardNumberId(),
                llResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );

    }

    @Override
    public Boolean cancelCard(CardCancelDto cardCancelDto) {
        String uri = getLlConfig().getCancelUrl() + cardCancelDto.getChannelCardId();
        LlResult llResult = checkResponse(
                HttpUtil.delete(
                        getLlConfig().getUrl(uri),
                        createDeleteHeader(uri)
                ),
                false
        );
        if (llResult.hasSuccess()) {
            userCardService.updateCardStatusByChannelCardId(
                    CardStatusEnum.CLOSE.getCode(),
                    cardCancelDto.getChannelCardId()
            );
        }
        return cardOrderService.closeCardComplete(
                cardCancelDto.getRequestId(),
                llResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public Boolean blockCard(String channelCardId, String requestId) {
        String uri = getLlConfig().getBlockUrl() + channelCardId;
        LlResult llResult = checkResponse(
                HttpUtil.post(
                        getLlConfig().getUrl(uri),
                        createPostHeader(uri, null),
                        HttpUtil.createBody()
                ),
                false
        );
        return cardOrderService.blockCardComplete(
                requestId,
                llResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public Boolean unblockCard(String channelCardId, String requestId) {
        String uri = getLlConfig().getUnBlockUrl() + channelCardId;
        LlResult llResult = checkResponse(
                HttpUtil.post(
                        getLlConfig().getUrl(uri),
                        createPostHeader(uri, null),
                        HttpUtil.createBody()
                ),
                false
        );
        return cardOrderService.unblockCardComplete(
                requestId,
                llResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public PageVo<PageTransactionVo> pagingTransaction(
            Integer pageNumber,
            Integer pageSize,
            String channelCardId,
            String transactionType,
            String status,
            Date startTime,
            Date endTime) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("pageNo", pageNumber);
        param.put("pageSize", pageSize);
        param.put("cardId", channelCardId);
        param.put("timeStart", startTime != null ? DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss") : null);
        param.put("timeEnd", endTime != null ? DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss") : null);
        String response = HttpUtil.get(
                getLlConfig().getUrl(getLlConfig().getPagingTransactionUrl()),
                param,
                createGetHeader(
                        getLlConfig().getPagingTransactionUrl(),
                        param
                )
        );
        LlResult llResult = checkResponse(response, true);
        JSONObject data = llResult.dataToEntity(JSONObject.class);
        Long totalCount = data.getLong("total");
        List<JSONObject> list = JSONUtil.toList(data.getString("list"), JSONObject.class);
        Integer totalPage = (int) Math.ceil((double) totalCount / pageSize);
        PageVo<PageTransactionVo> pageVo = new PageVo<>();
        pageVo.setPageNumber(pageNumber);
        pageVo.setPageSize(pageSize);
        pageVo.setTotal(totalCount);
        pageVo.setHasMore(pageNumber < totalPage);
        pageVo.setData(
                list.stream().map(it -> {
                    PageTransactionVo pageTransactionVo = new PageTransactionVo();
                    pageTransactionVo.setTransactionId(it.getString("transactionId"));
                    pageTransactionVo.setChannelCardId(it.getString("cardId"));
                    pageTransactionVo.setCardNumber(it.getString("last4CardNum"));
                    pageTransactionVo.setTransactionType(it.getString("type"));
                    pageTransactionVo.setTransactionStatus(it.getString("status"));
                    pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
                    pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
                    pageTransactionVo.setTransactionDate(
                            DateUtil.parse(it.getString("transactionTime"), DatePattern.NORM_DATETIME_PATTERN)
                    );
                    pageTransactionVo.setMerchantName(it.getString("merchantName"));
                    pageTransactionVo.setMcc(it.getString("mcc"));
                    pageTransactionVo.setMerchantCountry("");
                    pageTransactionVo.setRemark(it.getString("errorMsg"));
                    pageTransactionVo.setBillingAmount(it.getBigDecimal("billingAmount"));
                    pageTransactionVo.setBillingCurrency(it.getString("billingCurrency"));
                    pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
                    return pageTransactionVo;
                }).toList()
        );
        return pageVo;
    }


    @Override
    public PageVo<PageTransactionVo> pagingTransaction(Integer pageNumber, Integer pageSize, String transactionType, String status, Date startTime, Date endTime) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("pageNo", pageNumber);
        param.put("pageSize", pageSize);
        if (StringUtils.isNotBlank(transactionType)) {
            param.put("type", transactionType);
        }
        param.put("timeStart", startTime != null ? DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss") : null);
        param.put("timeEnd", endTime != null ? DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss") : null);
        String response = HttpUtil.get(
                getLlConfig().getUrl(getLlConfig().getPagingTransactionUrl()),
                param,
                createGetHeader(
                        getLlConfig().getPagingTransactionUrl(),
                        param
                )
        );
        LlResult llResult = checkResponse(response, true);
        JSONObject data = llResult.dataToEntity(JSONObject.class);
        Long totalCount = data.getLong("total");
        List<JSONObject> list = JSONUtil.toList(data.getString("list"), JSONObject.class);
        Integer totalPage = (int) Math.ceil((double) totalCount / pageSize);
        PageVo<PageTransactionVo> pageVo = new PageVo<>();
        pageVo.setPageNumber(pageNumber);
        pageVo.setPageSize(pageSize);
        pageVo.setTotal(totalCount);
        pageVo.setHasMore(pageNumber < totalPage);
        pageVo.setData(
                list.stream().map(it -> {
                    PageTransactionVo pageTransactionVo = new PageTransactionVo();
                    pageTransactionVo.setTransactionId(it.getString("transactionId"));
                    pageTransactionVo.setChannelCardId(it.getString("cardId"));
                    pageTransactionVo.setCardNumber(it.getString("last4CardNum"));
                    pageTransactionVo.setTransactionType(it.getString("type"));
                    pageTransactionVo.setTransactionStatus(it.getString("status"));
                    pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
                    pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
                    pageTransactionVo.setTransactionDate(DateUtil.parse(it.getString("transactionTime"), DatePattern.NORM_DATETIME_PATTERN));
                    pageTransactionVo.setMerchantName(it.getString("merchantName"));
                    pageTransactionVo.setMcc(it.getString("mcc"));
                    pageTransactionVo.setMerchantCountry("");
                    pageTransactionVo.setRemark(it.getString("errorMsg"));
                    pageTransactionVo.setBillingAmount(it.getBigDecimal("billingAmount"));
                    pageTransactionVo.setBillingCurrency(it.getString("billingCurrency"));
                    pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
                    return pageTransactionVo;
                }).toList()
        );
        return pageVo;
    }

    @Override
    public PageTransactionVo queryTransaction(String transactionId) {
        return null;
    }

    @Override
    public PageVo<PageClearingVo> pagingClearing(Integer pageNumber, Integer pageSize, String channelCardId, String transactionType, String status, Date startTime, Date endTime) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("pageNo", pageNumber);
        param.put("pageSize", pageSize);
        if (StringUtils.isNotBlank(transactionType)) {
            param.put("type", transactionType);
        }
        param.put("timeStart", startTime != null ? DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss") : null);
        param.put("timeEnd", endTime != null ? DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss") : null);
        String response = HttpUtil.get(
                getLlConfig().getUrl(getLlConfig().getPagingClearUrl()),
                param,
                createGetHeader(
                        getLlConfig().getPagingClearUrl(),
                        param
                )
        );
        LlResult llResult = checkResponse(response, true);
        JSONObject data = llResult.dataToEntity(JSONObject.class);
        Long totalCount = data.getLong("total");
        List<JSONObject> list = JSONUtil.toList(data.getString("list"), JSONObject.class);
        Integer totalPage = (int) Math.ceil((double) totalCount / pageSize);
        PageVo<PageClearingVo> pageVo = new PageVo<>();
        pageVo.setPageNumber(pageNumber);
        pageVo.setPageSize(pageSize);
        pageVo.setTotal(totalCount);
        pageVo.setHasMore(pageNumber < totalPage);
        pageVo.setData(
                list.stream().map(it -> {
                    PageClearingVo pageTransactionVo = new PageClearingVo();
                    pageTransactionVo.setTransactionId(it.getString("transactionId"));
                    pageTransactionVo.setChannelCardId(it.getString("cardId"));
                    pageTransactionVo.setCardNumber(it.getString("last4CardNum"));
                    pageTransactionVo.setTransactionType(it.getString("type"));
                    pageTransactionVo.setTransactionStatus(it.getString("status"));
                    pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
                    pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
                    pageTransactionVo.setClearingDate(
                            DateUtil.parse(it.getString("settlementTime"), DatePattern.NORM_DATETIME_PATTERN)
                    );
                    pageTransactionVo.setMerchantName(it.getString("merchantName"));
                    pageTransactionVo.setRemark(it.getString("errorMsg"));
                    pageTransactionVo.setBillingAmount(it.getBigDecimal("billingAmount"));
                    pageTransactionVo.setBillingCurrency(it.getString("billingCurrency"));
                    pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
                    return pageTransactionVo;
                }).toList()
        );
        return pageVo;
    }

    @Override
    public PageVo<PageClearingVo> pagingClearing(Integer pageNumber, Integer pageSize, String transactionType, String status, Date startTime, Date endTime) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("pageNo", pageNumber);
        param.put("pageSize", pageSize);
        if (StringUtils.isNotBlank(transactionType)) {
            param.put("type", transactionType);
        }
        param.put("timeStart", startTime != null ? DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss") : null);
        param.put("timeEnd", endTime != null ? DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss") : null);
        String response = HttpUtil.get(
                getLlConfig().getUrl(getLlConfig().getPagingClearUrl()),
                param,
                createGetHeader(
                        getLlConfig().getPagingClearUrl(),
                        param
                )
        );
        LlResult llResult = checkResponse(response, true);
        JSONObject data = llResult.dataToEntity(JSONObject.class);
        Long totalCount = data.getLong("total");
        List<JSONObject> list = JSONUtil.toList(data.getString("list"), JSONObject.class);
        Integer totalPage = (int) Math.ceil((double) totalCount / pageSize);
        PageVo<PageClearingVo> pageVo = new PageVo<>();
        pageVo.setPageNumber(pageNumber);
        pageVo.setPageSize(pageSize);
        pageVo.setTotal(totalCount);
        pageVo.setHasMore(pageNumber < totalPage);
        pageVo.setData(
                list.stream().map(it -> {
                    PageClearingVo pageTransactionVo = new PageClearingVo();
                    pageTransactionVo.setTransactionId(it.getString("transactionId"));
                    pageTransactionVo.setChannelCardId(it.getString("cardId"));
                    pageTransactionVo.setCardNumber(it.getString("last4CardNum"));
                    pageTransactionVo.setTransactionType(it.getString("type"));
                    pageTransactionVo.setTransactionStatus(it.getString("status"));
                    pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
                    pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
                    pageTransactionVo.setClearingDate(
                            DateUtil.parse(it.getString("settlementTime"), DatePattern.NORM_DATETIME_PATTERN)
                    );
                    pageTransactionVo.setMerchantName(it.getString("merchantName"));
                    pageTransactionVo.setRemark(it.getString("errorMsg"));
                    pageTransactionVo.setBillingAmount(it.getBigDecimal("billingAmount"));
                    pageTransactionVo.setBillingCurrency(it.getString("billingCurrency"));
                    pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
                    return pageTransactionVo;
                }).toList()
        );
        return pageVo;
    }

    @Override
    public PageClearingVo queryClearing(String transactionId) {
        return null;
    }

    @Override
    public BigDecimal queryAccountBalance() {
        try {
            HashMap<String, Object> param = HttpUtil.createParam();
            String response = HttpUtil.get(
                    getLlConfig().getUrl(getLlConfig().getQueryAccountBalanceUrl()),
                    param,
                    createGetHeader(
                            getLlConfig().getQueryAccountBalanceUrl(),
                            param
                    )
            );
            LlResult llResult = checkResponse(response, true);
            JSONObject data = llResult.dataToEntity(JSONObject.class);
            if (data == null) {
                log.error("查询账户余额返回数据为空");
                return BigDecimal.ZERO;
            }
            List<JSONObject> accountList = JSONUtil.toList(data.getString("accountList"), JSONObject.class);
            if (accountList == null || accountList.isEmpty()) {
                log.error("查询账户余额返回数据为空");
                return BigDecimal.ZERO;
            }
            JSONObject accountInfo = accountList.stream().filter(it -> it.getString("currency").equals("USD")).findFirst().orElse(null);
            if (accountInfo == null) {
                log.error("查询账户余额返回数据中没有找到USD账户信息");
                return BigDecimal.ZERO;
            }
            return accountInfo.getBigDecimal("amount");
        } catch (Exception e) {
            log.error("查询账户余额失败", e);
            return BigDecimal.ZERO;
        }
    }

    @Override
    public BigDecimal queryAccountBalance(String accountId) {

        return null;
    }

    @Override
    public BigDecimal queryCardBalance(String channelCardId) {
        try {
            CardInfoVo cardInfoVo = queryCardInfo(channelCardId);
            if (cardInfoVo == null) {
                log.error("查询卡信息失败，无法获取余额");
                return BigDecimal.ZERO;
            }
            return cardInfoVo.getBalance() != null ? cardInfoVo.getBalance() : BigDecimal.ZERO;
        } catch (Exception e) {
            log.error("查询卡余额失败", e);
            return BigDecimal.ZERO;
        }
    }

    @Override
    public String queryCardStatus(String channelCardId) {
        CardInfoVo cardInfoVo = queryCardInfo(channelCardId);
        if (cardInfoVo == null) {
            log.error("查询卡信息失败，无法获取状态");
            return CardStatusEnum.ABNORMAL.getCode();
        }
        String status = cardInfoVo.getCardStatus();
        if (status == null) {
            log.error("查询卡状态失败，返回状态为空");
            return CardStatusEnum.ABNORMAL.getCode();
        }
        return status;
    }

    @Override
    public PageVo<PageOperationLogVo> pagingOperationLog(Integer pageNumber, Integer pageSize, String type, Date startTime, Date endTime) {
        return null;
    }

    @Override
    public PageOperationLogVo queryOperationLog(String requestId) {
        return null;
    }

    @Override
    public CardInfoVo queryCardInfo(String channelCardId) {
        try {
            HashMap<String, Object> param = HttpUtil.createParam();
            String uri = getLlConfig().getQueryCardInfoUrl() + channelCardId;
            String response = HttpUtil.get(
                    getLlConfig().getUrl(uri),
                    param,
                    createGetHeader(
                            uri,
                            param
                    )
            );
            LlResult llResult = checkResponse(response, true);
            JSONObject data = llResult.dataToEntity(JSONObject.class);
            CardInfoVo cardInfoVo = new CardInfoVo();
            cardInfoVo.setRequestId(data.getString("cardName"));
            cardInfoVo.setChannelCardId(data.getString("cardId"));
            cardInfoVo.setCardStatus(statusConvert(data.getString("status")));
            cardInfoVo.setTotalLimit(data.getBigDecimal("lifeTimeLimit"));
            cardInfoVo.setBalance(data.getBigDecimal("lifeTimeLimitRemaining"));
            cardInfoVo.setBillingCurrency(data.getString("currency"));
            cardInfoVo.setCardType("SHARE");
            cardInfoVo.setCreateDate(null);
            cardInfoVo.setCardSecret(null);
            cardInfoVo.setBrand(data.getString("cardOrganization"));
            cardInfoVo.setCardholderId("");
            cardInfoVo.setNikeName(data.getString("cardName"));
            return cardInfoVo;
        } catch (Exception e) {
            log.error("查询卡信息失败", e);
            throw new ProgramException("查询信息失败");
        }
    }

    @Override
    public CardSecretVo queryCardSecret(String channelCardId) {
        return null;
    }

    @Override
    public CardSecretVo queryCardSecret(String channelCardId, String cardNumber, String expireDate) {
        try {
            HashMap<String, Object> param = HttpUtil.createParam();
            param.put("cardNo", cardNumber);
            param.put("expiryDate", expireDate);
            String uri = getLlConfig().getQueryCardSecretUrl() + channelCardId;
            String response = HttpUtil.get(
                    getLlConfig().getUrl(uri),
                    param,
                    createGetHeader(
                            uri,
                            param
                    )
            );
            LlResult llResult = checkResponse(response, true);
            JSONObject secretInfo = llResult.dataToEntity(JSONObject.class);
            return CardSecretVo.builder()
                    .cardNumber(cardNumber)
                    .cvv(Base64.decodeStr(secretInfo.getString("securityCode")))
                    .expireDate(expireDate)
                    .build();
        } catch (Exception e) {
            log.error("查询卡密失败", e);
            throw new ProgramException("查询信息失败");
        }
    }

    @Override
    public String createCardHolder(CreateCardHolderDto createCardHolderDto) {
        return "";
    }

    @Override
    public String updateCardHolder(UpdateCardHolderDto updateCardHolderDto) {
        return "";
    }

    @Override
    public Boolean transfer(TransferDto transferDto) {
        return null;
    }

    @Override
    public String createShareAccount(CreateShareAccountRequest createShareAccountRequest) {
        return "";
    }

    @Override
    public Boolean setTransactionLimit(SetTransactionLimitRequest setTransactionLimitRequest) {
        return null;
    }


    //申请中（APPLYING）
    //活跃（VALID）
    //已冻结（ABNORMAL）
    //已注销（CANCEL）
    //注销中（PRE_CANCEL）
    //已过期（EXPIRED）
    private String statusConvert(String status) {
        return switch (status) {
            case "VALID" -> CardStatusEnum.ACTIVE.getCode();
            case "APPLYING" -> CardStatusEnum.INACTIVE.getCode();
            case "ABNORMAL" -> CardStatusEnum.BLOCKED.getCode();
            case "CANCEL", "PRE_CANCEL", "EXPIRED" -> CardStatusEnum.CLOSE.getCode();
            default -> CardStatusEnum.ABNORMAL.getCode();
        };
    }
}
